home *** CD-ROM | disk | FTP | other *** search
- /*
- ** boot_atari.c -- This program loads the Atari Linux kernel and launches it.
- **
- ** Copyright 1994 by Björn Brauel and Roman Hodek
- **
- **
- ** This file is subject to the terms and conditions of the GNU General Public
- ** License. See the file README.legal in the main directory of this archive
- ** for more details.
- **
- */
-
- #include <osbind.h>
- #include <stddef.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <file.h>
- #include <types.h>
- #include <unistd.h>
-
- #define m68k
- #define PORTAR
-
- /* #define DEBUG */
-
-
- /* Atari bootstrap include file */
- #include "bootstra.h"
-
- /* required Atari linux include files */
- # include "a.out.h"
-
- #include "bootinfo.h"
-
- /* temporary stack size */
- #define TEMP_STACKSIZE 1024
-
- #define FAST_RAM_START 0x1000000
-
- long *fastram_top = (long *)0x5a4,
- *fastram_valid = (long *)0x5a8;
-
- /* The following variables are global, because they have to be accessed
- * after the stack has been changed.
- */
-
- struct bootinfo bi;
-
- long KSTART_MEM;
- long KMEM_SIZE;
- long kbi_offset;
-
- char *memptr;
- struct exec kexec;
- long rd_size;
-
- void *copy_addr;
- long copy_len;
-
-
-
- static void get_default_args( int *argc, char ***argv );
- static void waitkey( void );
-
-
- void usage(void)
- {
- fprintf (stderr, "Usage:\n"
- "\tbootstrap [-d] [-k kernel_executable] [-r ramdisk_file]"
- " [option...]\n");
- waitkey();
- exit (EXIT_FAILURE);
- }
-
- int main(int argc, char *argv[])
- {
- long i,memreq;
- int kfd,rfd;
- int debugflag=0;
- long offs;
- char *kernel_name = "vmlinux";
- char *ramdisk_name = NULL;
- void *stack;
- long savessp;
-
- rfd=-1;
- /* print the greet message */
- puts("Atari Linux Bootstrap version 0.6");
- puts("Copyright 1994 by Björn Brauel, Roman Hodek\n");
-
- if (argc == 1)
- get_default_args( &argc, &argv );
-
- /* ++roman: get kernel and ramdisk name from the command line */
- while( argc > 1 && argv[1][0] == '-' ) {
- switch( argv[1][1] ) {
- case 'k':
- if (argv[1][2]) {
- kernel_name = argv[1]+2;
- --argc; ++argv;
- }
- else if (argc > 2 && argv[2][0]) {
- kernel_name = argv[2];
- argc -= 2; argv += 2;
- }
- else
- usage();
- break;
- case 'r':
- if (argv[1][2]) {
- ramdisk_name = argv[1]+2;
- --argc; ++argv;
- }
- else if (argc > 2 && argv[2][0]) {
- ramdisk_name = argv[2];
- argc -= 2; argv += 2;
- }
- else
- usage();
- break;
- case 'd':
- debugflag = 1;
- --argc; ++argv;
- break;
- case '?':
- default:
- usage();
- }
- }
- --argc; ++argv;
-
- /* machine is Atari */
- bi.machtype = MACH_ATARI;
- KSTART_MEM = 0x000000L;
- KMEM_SIZE = 0x400000L;
-
- bi.cputype = CPU_68030;
- bi.cputype |= FPU_68881;
- bi.num_memory = 1;
- bi.memory[0].addr=KSTART_MEM;
- bi.memory[0].size=KMEM_SIZE;
-
- /* Test for TT Ram: I rely on undocumented system variables here,
- * hope the compatibility gods won't damn me forever...
- */
- savessp = Super( 0L );
- if (*fastram_valid == 0x1357bd13 && *fastram_top != 0) {
- bi.memory[bi.num_memory].addr = FAST_RAM_START;
- bi.memory[bi.num_memory].size = *fastram_top - FAST_RAM_START /* - PAGE_SIZE */;
- bi.num_memory++;
- }
- Super( savessp );
-
- /* Copy remaining arguments into the boot info */
- i = 0;
- bi.command_line[0] = 0;
- while (argc--) {
- if ((i+strlen(*argv)+1) < CL_SIZE) {
- i += strlen(*argv) + 1;
- if (bi.command_line[0])
- strcat (bi.command_line, " ");
- strcat (bi.command_line, *argv++);
- }
- }
-
- printf( "Command line is \"%s\"\n", bi.command_line );
-
- /* tell us where the kernel will go */
- printf("\nThe kernel will be located at %08lx\n", KSTART_MEM);
-
- /* open kernel executable and read exec header */
- if ((kfd = open (kernel_name, O_RDONLY)) == -1) {
- fprintf (stderr, "Unable to open kernel file %s\n", kernel_name);
- waitkey();
- exit (EXIT_FAILURE);
- }
-
- if (read (kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec)) {
- fprintf (stderr, "Unable to read exec header from %s\n",
- kernel_name);
- waitkey();
- exit (EXIT_FAILURE);
- }
-
- if (ramdisk_name) {
- if ((rfd = open (ramdisk_name, O_RDONLY)) == -1) {
- fprintf (stderr, "Unable to open ramdisk file %s\n",
- ramdisk_name);
- waitkey();
- exit (EXIT_FAILURE);
- }
- /* record ramdisk size */
- bi.ramdisk_size = (lseek (rfd, 0, SEEK_END)) >> 10;
- } else
- bi.ramdisk_size = 0;
-
- /* Ramdisk goes at the end of the last memory block */
- rd_size = bi.ramdisk_size << 10;
- bi.ramdisk_addr = bi.memory[bi.num_memory-1].addr +
- bi.memory[bi.num_memory-1].size - rd_size ;
-
- printf( "ramdisk size = %lx\n", (long)rd_size );
- printf( "ramdisk addr = %lx\n", (long)bi.ramdisk_addr );
-
- /* find offset to boot_info structure */
- offs = get_nlist (kernel_name, "_boot_info");
- if (offs==0) {
- perror ("get_nlist");
- waitkey();
- exit (EXIT_FAILURE);
- } else {
- kbi_offset = offs - kexec.a_entry;
- }
-
- memreq = kexec.a_text + kexec.a_data + rd_size;
- memptr = (char *)Malloc (memreq);
- if (!memptr) {
- fprintf (stderr, "Unable to allocate memory\n");
- waitkey();
- exit (EXIT_FAILURE);
- }
- printf( "Temporary load area is 0x%lx...0x%lx\n", (long)memptr, (long)(memptr+memreq-1) );
-
- { long load_st = (long)memptr,
- load_end = (long)memptr + memreq,
- dest_st = KSTART_MEM ,
- dest_end = KSTART_MEM + kexec.a_text + kexec.a_data +
- kexec.a_bss + 8;
-
- if ((load_end >= dest_st && load_end < dest_end) ||
- (dest_end >= load_st && dest_end < load_end)) {
- fprintf( stderr, "\nOVERLAPPING OF LOAD AND BOOT AREA!!!\n\n" );
- waitkey();
- exit( -1 );
- }
- if (bi.ramdisk_addr < load_end) {
- fprintf( stderr, "\nOVERLAPPING OF RAMDISK AND LOAD AREA!!!\n\n" );
- waitkey();
- exit( -1 );
- }
- }
-
- if (lseek (kfd, N_TXTOFF(kexec), SEEK_SET) == -1) {
- fprintf (stderr, "Failed to seek to text\n");
- Mfree ((void *)memptr);
- waitkey();
- exit (EXIT_FAILURE);
- }
- if (read (kfd, memptr + rd_size, kexec.a_text) != kexec.a_text) {
- fprintf (stderr, "Failed to read text\n");
- Mfree ((void *)memptr);
- waitkey();
- exit (EXIT_FAILURE);
- }
- if (lseek (kfd, N_DATOFF(kexec), SEEK_SET) == -1) {
- fprintf (stderr, "Failed to seek to data\n");
- Mfree ((void *)memptr);
- waitkey();
- exit (EXIT_FAILURE);
- }
- if (read (kfd, memptr + kexec.a_text + rd_size, kexec.a_data) != kexec.a_data) {
- fprintf (stderr, "Failed to read data\n");
- Mfree ((void *)memptr);
- waitkey();
- exit (EXIT_FAILURE);
- }
- close (kfd);
-
- if (rfd != -1) {
- if (lseek (rfd, 0, SEEK_SET) == -1) {
- fprintf (stderr, "Failed to seek to beginning of ramdisk file\n");
- Mfree ((void *)memptr);
- waitkey();
- exit (EXIT_FAILURE);
- }
- if (read (rfd, memptr, rd_size) != rd_size) {
- fprintf (stderr, "Failed to read ramdisk file\n");
- Mfree ((void *)memptr);
- waitkey();
- exit (EXIT_FAILURE);
- }
- close (rfd);
- }
-
- /* allocate temporary stack */
- stack = (void *)Malloc((long)TEMP_STACKSIZE);
- if (!stack) {
- fprintf (stderr, "Unable to allocate memory for stack\n");
- Mfree ((void *)memptr);
- waitkey();
- exit (EXIT_FAILURE);
- }
- printf( "Temporary stack is 0x%lx..0x%lx\n", (long)stack, (long)(stack + TEMP_STACKSIZE-1) );
-
- /* Allocate memory for copy routine. This must lie within the
- * destination address ranges (kernel mem and ramdisk mem).
- */
- copy_len = copy_kernel_end - copy_kernel;
- do {
- if (!(copy_addr = (void *)Malloc( copy_len ))) {
- fprintf( stderr, "Unable to allocate memory for copy routine.\n" );
- waitkey();
- exit (EXIT_FAILURE);
- }
- } while( (long)copy_addr < KSTART_MEM+kexec.a_text+kexec.a_data+kexec.a_bss+8 ||
- (long)copy_addr + copy_len > bi.ramdisk_addr );
-
- printf( "Copy routine will be located at %08lx.\n", (unsigned long)copy_addr );
- memcpy( copy_addr, copy_kernel, copy_len );
-
- if (debugflag) {
- if (bi.ramdisk_size)
- printf ("RAM disk at %#lx, size is %ldK\n", bi.ramdisk_addr,
- bi.ramdisk_size);
-
- printf ("\nKernel text at %#lx, code size %ld\n",
- KSTART_MEM + N_TXTADDR(kexec), (long)kexec.a_text);
- printf ("Kernel data at %#lx, data size %ld\n",
- KSTART_MEM + N_DATADDR(kexec), (long)kexec.a_data );
- printf ("Kernel bss at %#lx, bss size %ld\n",
- KSTART_MEM + N_BSSADDR(kexec), (long)kexec.a_bss );
-
- printf ("\nKernel boot_info is at offset %#lx, physical %#lx, virtual %#lx\n",
- kbi_offset, KSTART_MEM + kbi_offset, kbi_offset + kexec.a_entry );
-
- printf ("\nKernel entry is %#lx\n", (unsigned long)kexec.a_entry );
-
- printf ("ramdisk dest top is %#lx\n", KSTART_MEM);
- printf ("ramdisk lower limit is %#lx\n",
- (unsigned long)(memptr));
- printf ("ramdisk src top is %#lx\n",
- (unsigned long)(memptr + rd_size));
-
- printf( "Load area is 0x%lx .. 0x%lx\n", (long)(KSTART_MEM - rd_size),
- (long)(KSTART_MEM + kexec.a_text + kexec.a_data + kexec.a_bss) );
-
- printf( "\nFound %d memory blocks:\n", bi.num_memory );
- for( i = 0; i < bi.num_memory; ++i )
- printf( " 0x%08lx .. 0x%08lx (0x%lx bytes)\n",
- bi.memory[i].addr,
- bi.memory[i].addr + bi.memory[i].size - 1,
- bi.memory[i].size );
-
- printf ("\nType a key to continue the Linux boot...");
- fflush (stdout);
- getchar();
- }
-
- /* copy boot info into the kernel */
- memcpy( memptr + rd_size + kbi_offset, &bi, sizeof(bi) );
-
- /* wait for things to settle down */
- sleep(2);
-
- /* Go into supervisor state and change stack*/
- Super(0L);
- change_stack(stack + TEMP_STACKSIZE - sizeof(long));
- /* turn off caches */
- cache_off();
-
- /* turn off any mmu translation */
- disable_mmu ();
-
- /* Turn off Interrupts */
- raise_int();
-
- __asm__ __volatile__ (
- "movel %0,a6\n\t"
- "movel %1,a5\n\t"
- "movel %2,a4\n\t"
- "movel %3,d7\n\t"
- "movel %4,d6\n\t"
- "movel %5,d5\n\t"
- "movel %6,a0\n\t"
- "jmp a0@"
- : /* no outputs */
- : "g" (memptr), "g" (KSTART_MEM+8), "g" (bi.ramdisk_addr),
- "g" (kexec.a_text+kexec.a_data), "g" (kexec.a_bss),
- "g" (rd_size), "g" (copy_addr)
- );
-
- #if 0
- {
- /*
- * there may be problems here if the compiler optimizer
- * doesn't put these variables in registers, and the
- * stack space was allocated at the beginning of the function
- * and we've changed the stack.
- */
- unsigned char *csrc, *cdest, *climit;
- unsigned long *src, *dest, *limit;
-
- /*
- * copy the kernel text and data to their final resting place.
- * The text is padded out (in the a.out file) to a multiple of
- * the page size.
- */
-
- src = (unsigned long *)(memptr + rd_size);
- dest = (unsigned long*)(KSTART_MEM + 8L); /* first 8 bytes are ROM!! */
- limit = (unsigned long *)(memptr + rd_size + kexec.a_text +
- kexec.a_data + 8L);
- while (src < limit)
- *dest++ = *src++;
-
- /* clear kernel bss */
- dest = (unsigned long *)(KSTART_MEM + kexec.a_text + kexec.a_data + 8L);
- limit = dest + kexec.a_bss / sizeof(unsigned long);
- while (dest < limit)
- *dest++ = 0;
-
- /* copy the boot_info struct to the correct location */
- cdest = (unsigned char *)KSTART_MEM + 8L + kbi_offset;
- climit = cdest + sizeof (bi);
- csrc = (unsigned char *)&bi;
- while (cdest < climit)
- *cdest++ = *csrc++;
-
- /* copy the ramdisk at end of mem */
- dest = (unsigned long *)((u_long)bi.ramdisk_addr+(u_long)rd_size);
- limit = (unsigned long *)((u_long)memptr);
- src = (unsigned long *)((u_long)memptr + (u_long)rd_size);
- while (src > limit)
- *--dest = *--src;
-
- }
-
- /* jump to start of kernel */
- jump_to (KSTART_MEM + 8L);
- #endif
-
- /* NOTREACHED */
- return(0);
-
- }
-
-
-
- #define MAXARGS 30
-
- static void get_default_args( int *argc, char ***argv )
-
- { FILE *f;
- static char *nargv[MAXARGS];
- char arg[256], *p;
- int c, quote, state;
-
- if (!(f = fopen( "bootargs", "r" )))
- return;
-
- *argc = 0;
- *argv = nargv;
- nargv[(*argc)++] = "bootstra.ttp";
-
- quote = state = 0;
- while( (c = fgetc(f)) != EOF ) {
-
- if (state == 0) {
- /* outside args, skip whitespace */
- if (!isspace(c)) {
- state = 1;
- p = arg;
- }
- }
-
- if (state == 1) {
- /* inside an arg: copy it into 'arg', obeying quoting */
- if (!quote && (c == '\'' || c == '"'))
- quote = c;
- else if (quote && c == quote)
- quote = 0;
- else if (!quote && isspace(c)) {
- /* end of this arg */
- *p = 0;
- nargv[(*argc)++] = strdup(arg);
- state = 0;
- }
- else
- *p++ = c;
- }
- }
- if (state == 1) {
- /* last arg finished by EOF! */
- *p = 0;
- nargv[(*argc)++] = strdup(arg);
- }
- fclose( f );
-
- nargv[*argc] = 0;
- }
-
- long get_nlist(const char *fname, const char *symname)
- {
- int fd = open (fname, O_RDONLY);
- struct exec ex;
- struct nlist *nl, *syms;
- char *strs;
- long back;
- size_t filesize;
- long strsize, numsyms;
-
- if (fd == -1)
- return 0;
-
- read (fd, &ex, sizeof(ex));
- if (!ex.a_syms) {
- close (fd);
- return 0;
- }
-
- #ifdef DEBUG
- printf ("%ld bytes of symbol data\n", ex.a_syms);
- #endif
-
- syms = (struct nlist *)malloc (ex.a_syms);
- if (!syms) {
- close (fd);
- return 0;
- }
- filesize=lseek (fd, N_SYMOFF(ex), SEEK_SET);
- read (fd, syms, ex.a_syms);
- numsyms = ex.a_syms / sizeof (struct nlist);
- filesize = lseek (fd, 0L, SEEK_END);
- strsize = filesize - N_STROFF(ex);
- strs = (char *)malloc (strsize);
- if (!strs) {
- free (syms);
- close (fd);
- return 0;
- }
- lseek (fd, N_STROFF(ex), SEEK_SET);
- read (fd, strs, strsize);
- back=0;
-
-
- for (nl = syms; nl < syms + numsyms; nl++) {
- #ifdef DEBUG
- printf ("checking symbol number %d, name %s\n",
- nl - syms, strs + nl->n_un.n_strx);
- #endif
- if (strcmp (symname, strs + nl->n_un.n_strx) == 0
- && nl->n_type == N_BSS | N_EXT) {
- back = nl->n_value;
- break;
- }
- }
- free (strs);
- free (syms);
- close (fd);
- return back;
- }
-
-
- static void waitkey( void )
-
- {
- fprintf( stderr, "\nPress any key.\n" );
- while( !Bconstat(2) )
- ;
- (void)Bconin(2);
- }
-
-
-
-